package avicit.bdp.dgs.mdm.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.common.utils.CheckParaUtils;
import avicit.bdp.core.util.json.JSONUtils;
import avicit.bdp.dgs.mdm.dao.MdataChangeDao;
import avicit.bdp.dgs.mdm.dao.MdataMonitorDao;
import avicit.bdp.dgs.mdm.dao.MdataRApplicationDao;
import avicit.bdp.dgs.mdm.dto.*;
import avicit.bdp.dgs.mdm.utils.enums.OperType;
import avicit.bdp.dgs.mdm.utils.enums.PushStatus;
import avicit.platform6.commons.utils.ComUtil;
import avicit.platform6.commons.utils.PojoUtil;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.exception.DaoException;
import avicit.platform6.core.properties.PlatformConstant;
import avicit.platform6.core.rest.msg.QueryRespBean;
import avicit.platform6.modules.system.syslog.service.SysLogUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @金航数码科技有限责任公司
 * @作者：${tableInfo.classCreator}
 * @邮箱：${tableInfo.classMailbox}
 * @创建时间： 2023-12-06 11:02
 * @类说明：
 * @修改记录：
 */
@Service
public class MdataMonitorService extends BaseService<MdataMonitorDao, MdataMonitorDTO> {

    private static final Logger logger = LoggerFactory.getLogger(MdataMonitorService.class);

    @Value("${dgs.callbackUrl}")
    private String callbackUrl;

    @Autowired
    private MdataMonitorDao mdataMonitorDao;
    @Autowired
    private MdataChangeDao mdataChangeDao;
    @Autowired
    private MdataApplicationService mdataApplicationService;
    @Autowired
    private MdataChangeService mdataChangeService;
    @Autowired
    private MdataRApplicationDao mdataRApplicationDao;
    @Autowired
    private MdataLogService mdataLogService;
    @Autowired
    private TableService tableService;
    private static RestTemplate restTemplate;

    /**
     * 分页查询
     * @param pageNo
     * @param pageSize
     * @return
     * @throws Exception
     */
    @Transactional(readOnly = true)
    public QueryRespBean<MdataMonitorDTO> getPageList(String mdataId, String applicationId,
                                                      Integer operType, Integer pushStatus, Integer pageNo, Integer pageSize)
            throws Exception {
        QueryRespBean<MdataMonitorDTO> queryRespBean = new QueryRespBean<>();
        PageHelper.startPage(pageNo, pageSize);
        Page<MdataMonitorDTO> pageList = mdataMonitorDao.getPageList(mdataId, applicationId, operType, pushStatus);
        valueConvert(pageList.getResult());
        queryRespBean.setResult(pageList);
        BdpLogUtil.log4Query(queryRespBean);
        return queryRespBean;
    }

    private void valueConvert(List<MdataMonitorDTO> monitorList) {
        for (MdataMonitorDTO obj : monitorList) {
            obj.setOperTypeName(OperType.getDescByCode(obj.getOperType()));
            obj.setPushStatusName(PushStatus.getDescByCode(obj.getPushStatus()));
        }
    }

    /**
     * 新增对象
     *
     * @param dto 保存对象
     * @return String
     */
    @Transactional
    public String save(MdataMonitorDTO dto) {
        try {
            dto.setId(ComUtil.getId());
            PojoUtil.setSysProperties(dto, PlatformConstant.OpType.insert);
            this.insert(dto);
            // 记录日志
            SysLogUtil.log4Insert(dto);
            return dto.getId();
        } catch (Exception e) {
            throw new DaoException(e.getMessage(), e);
        }
    }

    /**
     * 修改对象部分字段
     *
     * @param dto 修改对象
     * @return int
     */
    @Transactional
    public int update(MdataMonitorDTO dto) {
        try {
            int count = this.updateByPrimaryKey(getUpdateDto(dto));
            if (count == 0) {
                throw new DaoException("数据失效，请重新更新");
            }
            return count;
        } catch (Exception e) {
            throw new DaoException(e.getMessage(), e);
        }
    }

    /**
     * 通过主键查询单条记录
     *
     * @param id 主键id
     */
    @Transactional(readOnly = true)
    public MdataMonitorDTO queryById(String id) {
        try {
            MdataMonitorDTO dto = this.selectByPrimaryKey(id);
            CheckParaUtils.checkDbObjectValidity(dto, logger, String.format("没有查到数据，请确保id:%s的监控数据是否存在", id));
            MdataApplicationDTO applicationDTO = mdataApplicationService.selectByPrimaryKey(dto.getApplicationId());
            MdataChangeDTO changeDTO = mdataChangeService.selectByPrimaryKey(dto.getChangeId());

            TableDTO mdata = tableService.selectByPrimaryKey(changeDTO.getMdataId());
            if(mdata != null){
                dto.setMdataName(mdata.getName());
            }

            if(applicationDTO != null){
                dto.setApplicationName(applicationDTO.getName());
            }
            if(changeDTO != null){
                dto.setOperTime(changeDTO.getOperTime());
                dto.setOperTypeName(OperType.getDescByCode(changeDTO.getOperType()));
                dto.setData(changeDTO.getData());
            }
            dto.setPushStatusName(PushStatus.getDescByCode(dto.getPushStatus()));

            // 记录日志
            if (dto != null) {
                SysLogUtil.log4Query(dto);
            }
            return dto;
        } catch (Exception e) {
            throw new DaoException(e.getMessage(), e);
        }
    }

    /**
     * 删除
     */
    @Transactional
    public void deleteById(String id){
        if (StringUtils.isEmpty(id)) {
            throw new BusinessException("id不能为空");
        }

        MdataMonitorDTO dto = this.selectByPrimaryKey(id);
        if (dto == null) {
            throw new BusinessException(String.format("id=%s的应用不存在", id));
        }
        // 记录日志
        BdpLogUtil.log4Delete(dto);
        // 删除数据
        this.deleteByPrimaryKey(id);
    }

    /**
     * 内部方法，获取修改的dto对象
     *
     * @param dto
     * @return
     */
    private MdataMonitorDTO getUpdateDto(MdataMonitorDTO dto) {
        MdataMonitorDTO oldDTO = this.selectByPrimaryKey(dto.getId());
        if (oldDTO == null) {
            throw new DaoException("数据不存在");
        }
        //记录日志
        SysLogUtil.log4Update(dto, oldDTO);
        PojoUtil.setSysProperties(dto, PlatformConstant.OpType.update);
        PojoUtil.copyProperties(oldDTO, dto, true);
        return oldDTO;
    }

    /**
     * 保存监控数据
     * @param changeId
     */
    @Transactional
    public void saveMonitorData(String changeId, String mdataId) {
        try {
            List<MdataRApplicationDTO> applicationList = mdataRApplicationDao.getMDataList(mdataId);
            if (CollectionUtils.isNotEmpty(applicationList)) {
                for(MdataRApplicationDTO app : applicationList){
                    MdataMonitorDTO dto = new MdataMonitorDTO();
                    dto.setId(ComUtil.getId());
                    dto.setChangeId(changeId);
                    dto.setApplicationId(app.getApplicationId());
                    dto.setPushStatus(PushStatus.WAIT_PUSH.getCode());
                    PojoUtil.setSysProperties(dto, PlatformConstant.OpType.insert);
                    this.insert(dto);
                }
            }
        } catch (Exception e) {
            throw new DaoException(e.getMessage(), e);
        }
    }

    /**
     * 组装待推送的数据
     * @param applicationId
     */
    public Map<String, Object> getPushData(String applicationId, List<MdataRInterfaceDTO> mdataList, Integer pageSize, MdataChangeDTO mdataChange) {
        Map<String, Object> map = new HashMap<>(4);
        if (CollectionUtils.isEmpty(mdataList)) {
            return map;
        }

        int pageNo = 1;
        if(pageSize == null){
            pageSize = 10;
        }
        JSONObject json = new JSONObject();
        List<String> monitorIdList = new ArrayList<>();
        for(MdataRInterfaceDTO dto : mdataList){
            List<MdataChangeDTO> mdataChangeList = new ArrayList<>();
            // 推送多条数据
            if(mdataChange == null){
                PageHelper.startPage(pageNo, pageSize);
                Page<MdataChangeDTO> pageList = mdataChangeDao.getMdataPageList(applicationId, dto.getMdataId());
                mdataChangeList = pageList.getResult();
            }else{
                mdataChangeList.add(mdataChange);
            }

            JSONArray jsonArray = new JSONArray();
            if (CollectionUtils.isNotEmpty(mdataChangeList)) {
                List<String> monitorIds = mdataChangeList.stream().map(MdataChangeDTO::getMonitorId).collect(Collectors.toList());
                monitorIdList.addAll(monitorIds);

                for(MdataChangeDTO change : mdataChangeList){
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("optType", change.getOperType());
                    jsonObject.put("data", JSONObject.parseObject(change.getData()));
                    jsonArray.add(jsonObject);
                }
            }

            String nodeName = dto.getNodeName();
            json.put(nodeName, jsonArray);
        }

        if (CollectionUtils.isEmpty(monitorIdList)) {
            return map;
        }

        map.put("data", json.toJSONString());
        map.put("monitorIdList", monitorIdList);
        return map;
    }

    /**
     * 回调函数
     * @param logId
     */
    @Transactional
    public Boolean callback(String logId, int status) {
        try{
            logger.info("回调函数参数logId:{},status:{}", logId, status);
            // 更新回调状态
            if (StringUtils.isEmpty(logId)) {
                throw new BusinessException("logId不能为空");
            }
            MdataLogDTO mdataLog =  mdataLogService.selectByPrimaryKey(logId);
            if (mdataLog == null) {
                throw new DaoException("日志数据不存在");
            }

            // 更新回调时间和状态
            mdataLog.setCallbackTime(new Date());
            mdataLog.setCallbackStatus(status);
            mdataLogService.updateByPrimaryKeySelective(mdataLog);

            String monitorIds = mdataLog.getMonitorIds();
            JSONArray array = JSONUtils.parseArray(monitorIds);
            List<String> monitorIdList = array.toJavaList(String.class);

            int pushStatus = 0;
            // 更新数据监控中推送状态
            if(status == 1){
                pushStatus = PushStatus.PUSHED.getCode();
            }else{
                pushStatus = PushStatus.PUSH_FAIL.getCode();
            }

            mdataMonitorDao.updatePushStatusAndTimeById(pushStatus, new Date(), monitorIdList);

            logger.info("回调函数处理成功");
            return true;
        }catch (Exception e){
            String msg = String.format("回调函数处理失败,%s", e.getMessage());
            logger.error(msg);
            throw new BusinessException(msg);
        }
    }

    /**
     * 更新推送状态
     */
    @Transactional
    public void updatePushStatusById(Integer pushStatus, List<String> idList) {
        mdataMonitorDao.updatePushStatusById(pushStatus, idList);
    }

    /**
     * 更新推送状态和时间
     */
    @Transactional
    public void updatePushStatusAndTimeById(Integer pushStatus, Date pushTime, List<String> idList) {
        mdataMonitorDao.updatePushStatusAndTimeById(pushStatus, pushTime, idList);
    }

    /**
     * 测试接收主数据接口
     */
    public void getDataList(String data, HttpServletRequest request) throws Exception {
        logger.info("接收的主数据是:{}", data);
        String applicationCode = request.getHeader("applicationCode");
        String authCode = request.getHeader("authCode");
        String logId = request.getHeader("logId");
        logger.info("applicationCode:{}", applicationCode);
        logger.info("authCode:{}", authCode);
        logger.info("logId:{}", logId);

        // 模拟处理时间
        Thread.sleep(10 * 1000);

        // 处理完成回调函数
        call(applicationCode, authCode, logId);
    }

    private void call(String applicationCode, String authCode, String logId){
        try{
            SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
            requestFactory.setConnectTimeout(80 * 1000);
            requestFactory.setReadTimeout(80 * 1000);
            restTemplate = new RestTemplate(requestFactory);
            List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
            messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
            messageConverters.add(new FormHttpMessageConverter());

            MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
            converter.setSupportedMediaTypes(Arrays.asList(MediaType.ALL));
            messageConverters.add(converter);
            restTemplate.getMessageConverters().addAll(messageConverters);

            // 创建一个头部对象
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.valueOf("application/json;charset=UTF-8"));
            List<MediaType> mediaTypeList = new ArrayList<>();
            mediaTypeList.add(MediaType.ALL);
            headers.setAccept(mediaTypeList);
            headers.add("applicationCode", applicationCode);
            headers.add("authCode", authCode);
            HttpEntity httpEntity = new HttpEntity<Object>("", headers);

            String url = callbackUrl+"?logId="+logId+"&status=1";
            ResponseEntity<String> result = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
        }catch (Exception e){
            e.printStackTrace();
            String msg = String.format("回调API接口失败,%s", e.getMessage());
            throw new BusinessException(msg);
        }
    }

}
